package com.example.simplenet;

import java.io.BufferedInputStream;
import java.io.ObjectInputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends FragmentActivity {

	private ImageView mAttackImageView;
	private TextView mWood;
	private TextView mIron;
	private TextView mStone;
	private TextView mGold;
	private TextView mDiamonds;
	private TextView mProvince;
	
	public boolean mAttacksSheduled = false;

	private static final String TAG = MainActivity.class.getSimpleName();
	public static final String FILENAME = "abandoned.dat";
	
	Messenger mService = null;
	final Messenger mMessenger = new Messenger(new IncomingHandler(this));
	private boolean mIsBound;
	
	static class IncomingHandler extends Handler {
		final WeakReference<MainActivity> mActivity;
		
		public IncomingHandler(MainActivity activity) {
			mActivity = new WeakReference<MainActivity>(activity);
		}
		
        @Override
        public void handleMessage(Message msg) {
        	Bundle bundle = msg.getData();
            switch (msg.what) {
            case ConnectionMan.MSG_SET_RESOURCES:
        		mActivity.get().updateResources(bundle.getString("wood"), 
        				bundle.getString("iron"), bundle.getString("stone"), 
        				bundle.getString("gold"), bundle.getString("diamonds"));
                break;
            case ConnectionMan.MSG_SET_PROVINCE:
            	mActivity.get().updateProvince(bundle.getString("province"));
            	break;
            case ConnectionMan.MSG_UPDATE_ATTACK_ICON:
            	mActivity.get().showAttackIndicator(ArmyController.isUnderAttack());
            	break;
            case ConnectionMan.MSG_RESET_PROVINCE_VIEW:
            	mActivity.get().onProvinceChanged();
            	break;
            case ConnectionMan.MSG_START_PARSE_TABLE:
            	mActivity.get().parseTable(bundle.getString("html"));
            	break;
            case ConnectionMan.MSG_UPDATE_ABANDONED:
            	mActivity.get().updateAbandoned(bundle.getBoolean("changed"));
            	break;
            case ConnectionMan.MSG_SHOW_TOAST:
            	mActivity.get().showToast(bundle.getString("message"), bundle.getBoolean("isShort"));
            	break;
            case ConnectionMan.MSG_UPDATE_BUTTONS:
            	mActivity.get().updateButtons(ConnectionMan.isServiceRunning());
            	break;
            case ConnectionMan.MSG_UPDATE_MISSIONS:
            	mActivity.get().updateMissions();
            	break;
            default:
                super.handleMessage(msg);
            }
        }
    }
	
	private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            Log.i(TAG, "onServiceConnected");
            updateButtons(true);
            mService = new Messenger(service);
            try {
                Message msg = Message.obtain(null, ConnectionMan.MSG_REGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
            	
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            Log.i(TAG, "onServiceDisconnected");
            updateButtons(false);
            mService = null;
        }
    };

	@SuppressWarnings("unchecked")
	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		try {
			ObjectInputStream ois = new ObjectInputStream(
					new BufferedInputStream(openFileInput(FILENAME)));
			AbandonedController.getInstance(this).setAbandoned(
					(ArrayList<AbandonedInfo>) ois.readObject());
			ois.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		mAttackImageView = (ImageView) findViewById(R.id.attackImageView);
		mWood = (TextView) findViewById(R.id.woodTextView);
		mIron = (TextView) findViewById(R.id.ironTextView);
		mStone = (TextView) findViewById(R.id.stoneTextView);
		mGold = (TextView) findViewById(R.id.goldTextView);
		mDiamonds = (TextView) findViewById(R.id.diamondTextView);
		mProvince = (TextView) findViewById(R.id.provinceTextView);
		mProvince.setOnClickListener(new OnClickListener() {

			@SuppressLint("InflateParams")
			@Override
			public void onClick(View v) {

				AlertDialog.Builder builder = new AlertDialog.Builder(
						MainActivity.this);
				LayoutInflater inflater = getLayoutInflater();
				View newView = inflater.inflate(R.layout.province_choose, null);
				builder.setView(newView).setNegativeButton(
						android.R.string.cancel,
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {

								dialog.dismiss();
							}
						});
				LinearLayout layout = (LinearLayout) newView
						.findViewById(R.id.provinceChooseLayout);

				final AlertDialog dialog = builder.create();

				LinearLayout layout2 = null;
				int marginDp = getDp(5);
				SparseArray<String> provinces = ArmyController.getProvincesInfo();
				if (provinces == null)
					return;
				for (int i = 0; i < provinces.size(); ++i) {
					if (i % 4 == 0) {
						layout2 = new LinearLayout(getApplicationContext());
						layout2.setOrientation(LinearLayout.HORIZONTAL);
						layout2.setGravity(Gravity.CENTER);
						LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams(
								LinearLayout.LayoutParams.WRAP_CONTENT,
								LinearLayout.LayoutParams.WRAP_CONTENT);
						lParams.setMargins(0, marginDp * 100, 0, marginDp * 100);
						layout.setLayoutParams(lParams);
						layout.addView(layout2);
					}
					RelativeLayout provLayout = new RelativeLayout(
							getApplicationContext());
					RelativeLayout.LayoutParams rParams = new RelativeLayout.LayoutParams(
							RelativeLayout.LayoutParams.WRAP_CONTENT,
							RelativeLayout.LayoutParams.WRAP_CONTENT);
					rParams.setMargins(marginDp * 100, 0, marginDp * 100, 0);
					provLayout.setLayoutParams(rParams);

					ImageView img = new ImageView(getApplicationContext());
					img.setBackgroundResource(R.drawable.province);
					img.setId(i + 1);
					provLayout.addView(img);

					TextView textView = new TextView(getApplicationContext());
					textView.setTextAppearance(getApplicationContext(),
							android.R.style.TextAppearance_Large);
					final int provinceName = provinces.keyAt(i);
					textView.setText(String.valueOf(provinceName));
					textView.setGravity(Gravity.CENTER);
					textView.setTextColor(getResources().getColor(
							android.R.color.black));
					RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
							RelativeLayout.LayoutParams.WRAP_CONTENT,
							RelativeLayout.LayoutParams.WRAP_CONTENT);
					params.addRule(RelativeLayout.ALIGN_BOTTOM, img.getId());
					params.addRule(RelativeLayout.ALIGN_TOP, img.getId());
					params.addRule(RelativeLayout.ALIGN_LEFT, img.getId());
					params.addRule(RelativeLayout.ALIGN_RIGHT, img.getId());
					textView.setLayoutParams(params);
					provLayout.setOnClickListener(new OnClickListener() {

						@Override
						public void onClick(View v) {

							changeProvince(
									ArmyController.getProvincesInfo().get(
											provinceName), false);
							dialog.dismiss();
						}
					});
					provLayout.addView(textView);
					layout2.addView(provLayout);
				}
				dialog.show();
			}
		});

		if (findViewById(R.id.containerFrameLayout) != null) {

			if (savedInstanceState != null)
				return;

			ButtonFragment buttonFragment = new ButtonFragment();
			buttonFragment.setArguments(getIntent().getExtras());
			getSupportFragmentManager()
					.beginTransaction()
					.add(R.id.containerFrameLayout, buttonFragment,
							"ButtonFragment").commit();
		}

		restoreMe(savedInstanceState);
		
        checkIfServiceIsRunning();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putBoolean("attackStatus", mAttackImageView.getVisibility() == View.VISIBLE);
		outState.putString("wood", mWood.getText().toString());
		outState.putString("iron", mIron.getText().toString());
		outState.putString("stone", mStone.getText().toString());
		outState.putString("gold", mGold.getText().toString());
		outState.putString("diamond", mDiamonds.getText().toString());
		outState.putString("province", mProvince.getText().toString());
	}
	
	private void restoreMe(Bundle savedInstanceState) {
		if (savedInstanceState != null) {
			mAttackImageView.setVisibility(savedInstanceState.getBoolean("attackStatus") ? View.VISIBLE : View.INVISIBLE);
			mWood.setText(savedInstanceState.getShort("wood"));
			mWood.setText(savedInstanceState.getShort("iron"));
			mWood.setText(savedInstanceState.getShort("stone"));
			mWood.setText(savedInstanceState.getShort("gold"));
			mWood.setText(savedInstanceState.getShort("diamond"));
			mWood.setText(savedInstanceState.getShort("province"));
		}
	}

	private void checkIfServiceIsRunning() {
		if (ConnectionMan.isServiceRunning()) {
			doBindService();
		}
	}

	private void doBindService() {
		Log.i(TAG, "doBindService");
		bindService(new Intent(this, ConnectionMan.class), mConnection, Context.BIND_AUTO_CREATE);
		mIsBound = true;
	}
	
	public void sendMessageToService(int what, Bundle bundle) {
        if (mIsBound) {
            if (mService != null) {
                try {
                    Message msg = Message.obtain(null, what);
                    msg.replyTo = mMessenger;
                    msg.setData(bundle);
                    mService.send(msg);
                } catch (RemoteException e) {
                	e.printStackTrace();
                }
            }
        }
    }
	
	private void doUnbindService() {
		Log.i(TAG, "doUnbindService");
        if (mIsBound) {
            // If we have received the service, and hence registered with it, then now is the time to unregister.
            if (mService != null) {
                try {
                    Message msg = Message.obtain(null, ConnectionMan.MSG_UNREGISTER_CLIENT);
                    msg.replyTo = mMessenger;
                    mService.send(msg);
                } catch (RemoteException e) {
                    // There is nothing special we need to do if the service has crashed.
                }
            }
            // Detach our existing connection.
            try {
            	unbindService(mConnection);
            } catch (IllegalArgumentException ex) {
            	
            }
            mIsBound = false;
        }
    }

	private void reloadPage() {
		sendMessageToService(ConnectionMan.MSG_RELOAD, null);
	}

	private void updateResources(String wood, String iron, String stone,
			String gold, String diamonds) {

		mWood.setText(wood);
		mIron.setText(iron);
		mStone.setText(stone);
		mGold.setText(gold);
		mDiamonds.setText(diamonds);
	}

	private void updateProvince(String province) {
		mProvince.setText(province);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {

		switch (item.getItemId()) {
		case R.id.action_test_alert:
			showAttackIndicator(true);
			Notifier.attackNotify(this);
			return true;
		case R.id.action_reload:
			reloadPage();
			return true;
		case R.id.action_exit:
			finish();
			return true;
		default:
			return super.onMenuItemSelected(featureId, item);
		}
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		try { 
			doUnbindService();
		} catch (Throwable t) {
			Log.e(TAG, "Failed to unbind.", t);
		}
	}

	private void changeProvince(String province, boolean moveArmyAfterWards) {
		Bundle bundle = new Bundle();
		bundle.putString("province", province);
		bundle.putBoolean("moveArmyAfterwards", moveArmyAfterWards);
		sendMessageToService(ConnectionMan.MSG_CHANGE_PROVINCE, bundle);
	}
	
	private int getDp(int pixels) {
		return (int) (getApplication().getResources().getDisplayMetrics().density * pixels);
	}

	private void onProvinceChanged() {
		try {
			getSupportFragmentManager().popBackStack();
		} catch (IllegalStateException ex) {
			Fragment fragment = getSupportFragmentManager().findFragmentByTag(
					"AbandonedFragment");
			if (fragment == null)
				fragment = getSupportFragmentManager().findFragmentByTag(
					"BuildingFragment");
			if (fragment == null)
				fragment = getSupportFragmentManager().findFragmentByTag(
						"ArmyFragment");
			if (fragment != null)
				((MyFragment) fragment).onResumePopBackStack();
		}
	}

	private void parseTable(String response) {
		Fragment fragment = getSupportFragmentManager().findFragmentByTag(
				"BuildingFragment");
		if (fragment != null)
			((BuildingFragment) fragment).parseTable(response);
	}
	
	private void updateAbandoned(boolean changed) {
		Fragment fragment = getSupportFragmentManager().findFragmentByTag(
				"AbandonedFragment");
		if (fragment != null) {
			AbandonedFragment abandonedFragment = (AbandonedFragment) fragment;
			abandonedFragment.setText(AbandonedController.getInstance(this)
					.getText());
			if (changed)
				abandonedFragment.layout();
		}
	}
	
	private void showToast(String message, boolean isShort) {
		Toast.makeText(this, message, isShort ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
	}

	private void showAttackIndicator(final boolean visible) {
		runOnUiThread(new Runnable() {

			@Override
			public void run() {

				mAttackImageView.setVisibility(visible ? View.VISIBLE
						: View.INVISIBLE);
			}
		});
	}

	private void updateButtons(boolean running) {

		Fragment fragment = getSupportFragmentManager().findFragmentByTag(
				"ButtonFragment");
		if (fragment != null)
			((ButtonFragment) fragment).updateButtons(running);
	}

	private void updateMissions() {

		Fragment fragment = getSupportFragmentManager().findFragmentByTag(
				"MissionsFragment");
		if (fragment != null)
			((MissionsFragment) fragment).updateMissions();
	}
	
	public void startAndBind() {
		startService(new Intent(this, ConnectionMan.class));
		doBindService();
	}

	public void stopService() {
		unbindService(mConnection);
		stopService(new Intent(this, ConnectionMan.class));
        updateButtons(false);
	}

	public void pauseService() {
		sendMessageToService(ConnectionMan.MSG_PAUSE_SERVICE, null);
	}

	public void getMissions() {
		sendMessageToService(ConnectionMan.MSG_GET_MISSIONS, null);
	}
}
